{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#-*- coding: utf-8 -*-"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据类型的底层实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#列表的底层实现\n",
    "#引用数组的概念，列表内的元素可以分散的存储在内存中，列表存储的，实际上是这些元素的地址，这些地址的存储在内存中是连续的\n",
    "list_1 = [1,[22,33,44],(5,6,7),{\"name\":\"Sarah\"}]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#浅拷贝只是将这些地址复制了一份，但是这些地址所指向的内容是相同的\n",
    "list_2 = list(list_1) #浅拷贝 与list_1.copy()功能一样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, [22, 33, 44], (5, 6, 7), {'name': 'Sarah'}, 100]\n",
      "[1, [22, 33, 44], (5, 6, 7), {'name': 'Sarah'}, 'n']\n"
     ]
    }
   ],
   "source": [
    "#新增元素\n",
    "list_1.append(100) #对list_1新存储一个地址，指向100\n",
    "list_2.append(\"n\")#对list_2新存储一个地址，指向n\n",
    "print (list_1)\n",
    "print (list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list_1:  [10, [22, 33, 44], (5, 6, 7), {'name': 'Sarah'}, 100]\n",
      "list_2:  [20, [22, 33, 44], (5, 6, 7), {'name': 'Sarah'}, 'n']\n"
     ]
    }
   ],
   "source": [
    "#修改元素 将地址改为已经修改元素的地址\n",
    "list_1[0] = 10\n",
    "list_2[0] = 20\n",
    "print(\"list_1: \",list_1)\n",
    "print(\"list_2: \",list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list_1:  [10, [22, 33, 55, 66], (5, 6, 7), {'name': 'Sarah'}, 100]\n",
      "list_2:  [20, [22, 33, 55, 66], (5, 6, 7), {'name': 'Sarah'}, 'n']\n"
     ]
    }
   ],
   "source": [
    "#对列表型元素进行操作，由于两个地址指向同一个列表行元素的地址，所以列表型元素的内容修改，两个列表内容都会修改\n",
    "list_1[1].remove(44)\n",
    "list_2[1] += [55,66]\n",
    "print(\"list_1: \",list_1)\n",
    "print(\"list_2: \",list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list _1: [10, [22, 33, 55, 66], (5, 6, 7), {'name': 'Sarah'}, 100]\n",
      "list_2:  [20, [22, 33, 55, 66], (5, 6, 7, 8, 9), {'name': 'Sarah'}, 'n']\n"
     ]
    }
   ],
   "source": [
    "#对元组型元素进行修改，注意元组是不可变的，对元组进行操作，会生成一个新的元组，原来的元组并没有改变\n",
    "list_2[2] += (8,9)\n",
    "print (\"list _1:\",list_1)\n",
    "print (\"list_2: \",list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list_1:  [10, [22, 33, 55, 66], (5, 6, 7), {'name': 'Sarah', 'age': 18}, 100]\n",
      "list_2:  [20, [22, 33, 55, 66], (5, 6, 7, 8, 9), {'name': 'Sarah', 'age': 18}, 'n']\n"
     ]
    }
   ],
   "source": [
    "#对字典进行操作，原理和对列表进行操作一样，两个列表都会改变\n",
    "list_1[-2][\"age\"] = 18\n",
    "print(\"list_1: \",list_1)\n",
    "print(\"list_2: \",list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list_1:  [1, [22, 33, 44], (5, 6, 7), {'name': 'Sarah', 'age': 18}]\n",
      "list_2:  [1, [22, 33, 44, 55], (5, 6, 7), {'name': 'Sarah'}]\n"
     ]
    }
   ],
   "source": [
    "#引入深拷贝 深拷贝将所有层级的相关元素全部复制，完全分开，泾渭分明，避免了上述问题\n",
    "import copy\n",
    "list_1 = [1,[22,33,44],(5,6,7),{\"name\":\"Sarah\"}]\n",
    "list_2 = copy.deepcopy(list_1)\n",
    "\n",
    "list_1[-1][\"age\"] = 18\n",
    "list_2[1].append(55)\n",
    "\n",
    "print(\"list_1: \",list_1)\n",
    "print(\"list_2: \",list_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['2', '2', 'd', 'd', '包']\n"
     ]
    }
   ],
   "source": [
    "#神秘的字典 字典的查找操作远远快于列表\n",
    "#字典通过稀疏数组来实现值的存储和访问\n",
    "#字典的创建过程 第一步：创建一个散列表（稀疏数组 N >>需要存储的值 n）\n",
    "#第二步  根据计算的散列值确定其在散列表中的位置 极个别时候散列值会发生冲突，则内部有相应的解决冲突方法\n",
    "#第三步 在该位置上存入值 访问的同理 而列表是从头开始顺序查找 所以速度比字典慢很多\n",
    "\n",
    "#字符串的存储通过紧凑数组直接存储元素\n",
    "#列表遍历需要注意的问题，注意用这种方式无法删除列表中所有的d，因为每一次删除之后，列表都会改变，但是for循环还是按照顺序循环的\n",
    "#比如删除第一个d之后，新的列表就是[\"d\",\"d\",\"2\",\"2\",\"d\",\"d\",\"包\"],但是for循环记得已经取过0个元素了，所以开始取第一个元素，于是少取了一个d\n",
    "alist = [\"d\",\"d\",\"d\",\"2\",\"2\",\"d\",\"d\",\"包\"]\n",
    "for s in alist:\n",
    "    if s == \"d\":\n",
    "        alist.remove(\"d\") #删除列表中第一次出现的该元素\n",
    "print(alist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['2', '2', '包']\n"
     ]
    }
   ],
   "source": [
    "#解决办法，使用负向索引,从-8访问到-1,先访问-8，再访问-7，以此类推，可以将所有d都删除掉\n",
    "alist1 = [\"d\",\"d\",\"d\",\"2\",\"2\",\"d\",\"d\",\"包\"]\n",
    "for i in range(-len(alist),0):\n",
    "    if alist[i] == \"d\":\n",
    "        alist.remove(alist[i])\n",
    "print(alist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n",
      "[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n"
     ]
    }
   ],
   "source": [
    "#多维列表的创建,注意乘以5是浅拷贝\n",
    "ls = [[0]*10]*5\n",
    "print (ls)\n",
    "ls[0][0] = 1\n",
    "print(ls)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n",
      "[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n"
     ]
    }
   ],
   "source": [
    "#使用解析语法创建多维列表,在中括号里面，后面是对可迭代对象的遍历，每次取一个元素，执行相应的操作\n",
    "#这个例子中，是每次取一个元素，就执行一次[0]*10 操作，创建一个[0]*10数组，最终生成一个5*10数组\n",
    "ls = [[0]*10 for i in range(5)]\n",
    "print (ls)\n",
    "ls[0][0] =1\n",
    "#因为各个数组是独立创建的，所有只修改其中一个\n",
    "print(ls)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解析语法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 9, 25, 49, 81, 121, 169, 225, 289, 361]\n",
      "[1, 9, 25, 49, 81, 121, 169, 225, 289, 361]\n"
     ]
    }
   ],
   "source": [
    "#解析语法的基本结构 以列表解析为例子（也称为列表推导）\n",
    "#[expression   for value in iterable   if condition]\n",
    "#三要数 ：表达式，可迭代对象，if条件\n",
    "#执行过程：从可迭代对象中拿出一个元素，通过if条件（如果有的话），对元素进行筛选，若通过筛选，则把元素传递给表达式，若未通过，则进入下一次迭代\n",
    "# 将表达式产生的结果作为列表的一个元素，直到迭代对象迭代结束，返回新创建的列表\n",
    "#等价于如下代码\n",
    "#result = []\n",
    "#for value in iterabe:\n",
    "#    if condition:\n",
    "#        result.append(expression)\n",
    "#例子 求20以内的奇数的平方\n",
    "squares = []\n",
    "for i in range(1,21):\n",
    "    if i%2 == 1:\n",
    "        squares.append(i**2)\n",
    "print(squares)\n",
    "print ([i**2  for i in range(1,21) if i%2 == 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 4, 9]\n"
     ]
    }
   ],
   "source": [
    "#支持多变量\n",
    "x = [1,2,3]\n",
    "y = [1,2,3]\n",
    "results = [i*j for i,j in zip(x,y)]\n",
    "print (results)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['black S', 'black M', 'black L', 'while S', 'while M', 'while L']\n"
     ]
    }
   ],
   "source": [
    "#支持嵌套循环\n",
    "colors = [\"black\",\"while\"]\n",
    "sizes = [\"S\",\"M\",\"L\"]\n",
    "tshirts = [\"{} {}\".format(color,size) for color in colors for size in sizes]\n",
    "print (tshirts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 :  0\n",
      "1 :  1\n",
      "2 :  4\n",
      "3 :  9\n",
      "4 :  16\n",
      "5 :  25\n",
      "6 :  36\n",
      "7 :  49\n",
      "8 :  64\n",
      "9 :  81\n"
     ]
    }
   ],
   "source": [
    "#其它解析语法的例子\n",
    "#解析语法构造字典（字典推导）\n",
    "squares = {i:i**2 for i in range(10)}\n",
    "for k,v in squares.items():\n",
    "    print(k,\": \",v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}\n"
     ]
    }
   ],
   "source": [
    "#解析语法构造集合（集合推导）\n",
    "squares = {i**2 for i in range(10)}\n",
    "print(squares)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "4\n",
      "9\n",
      "16\n",
      "25\n",
      "36\n",
      "49\n",
      "64\n",
      "81\n"
     ]
    }
   ],
   "source": [
    "#生成器推导 可以进行迭代\n",
    "squares = (i**2 for i in range(10))\n",
    "for square in squares:\n",
    "    print(square)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n"
     ]
    }
   ],
   "source": [
    "#条件表达式  expr1 if condition else expr2  如果条件成立，就执行expr1 ，否则执行expr2\n",
    "#将n的绝对值赋值给x\n",
    "n = -10\n",
    "x = n if n>=0 else -n\n",
    "print (x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 三大神器 生成器 迭代器 装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5050\n"
     ]
    }
   ],
   "source": [
    "#生成器 如果要计算列表中1到100每个数的平方，采用列表迭代的方式，占用大量内存，此时可以使用生成器\n",
    "#生成器采用惰性计算，海量数据，不需要存储 一边迭代一边计算 每次只算出当次需要的值，后面的值用到的时候再计算\n",
    "#生成器实际上一直在执行next（）操作，取到下一个值，直到无值可取\n",
    "#squares = (i**2 for i in range(10000))\n",
    "#for i in squares\n",
    "#    pass\n",
    "#采用生成器无需显示存储全部数据，节省内存\n",
    "print (sum(i for i in range(101)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n",
      "8\n",
      "13\n",
      "21\n",
      "34\n",
      "55\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#生成器函数 yield\n",
    "#以生成斐波那契数列为例子 数列的前两个元素为1,1,之后的元素为其前两个元素之和\n",
    "def fib(max):\n",
    "    ls = []\n",
    "    n,a,b = 0,1,1\n",
    "    while n < max:\n",
    "        #ls.append(a)\n",
    "        print (a) #每次打印输出斐波那契数列就可以了\n",
    "        a,b = b,a+b\n",
    "        n = n+1\n",
    "    return ls\n",
    "\n",
    "fib(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n",
      "8\n",
      "13\n",
      "21\n",
      "34\n",
      "55\n"
     ]
    }
   ],
   "source": [
    "#使用yield，遇到yield语句，会将后面的元素返回，当它执行完返回后，就会停在这里，知道进行下一次next操作，它会从停止的地方继续执行\n",
    "def fib(max):\n",
    "    n,a,b = 0,1,1\n",
    "    while n < max:\n",
    "        yield a\n",
    "        a,b = b,a+b\n",
    "        n = n +1\n",
    "fib(10)\n",
    "for i in fib(10):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "#迭代器\n",
    "#可直接用于for循环的对象称为可迭代对象：iterable\n",
    "#列表 元组 字符串 字典 集合 文件 都是可迭代对象 我们可以使用isinstance()判断一个对象是否是iterable对象\n",
    "from collections import Iterable\n",
    "print(isinstance([1,2,3],Iterable))\n",
    "print(isinstance({\"name\":\"Sarah\"},Iterable))\n",
    "print(isinstance('Python',Iterable))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "#生成器也是可迭代对象\n",
    "squares =  (i**2 for i in range(5))\n",
    "print(isinstance(squares,Iterable))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "#生成器不但可以用于for循环，还可以被next()函数调用\n",
    "#每调用一次next函数，取出一个元素，直到没有数据可取，抛出StopIteration\n",
    "print(next(squares))\n",
    "print(next(squares))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "#可以被next()函数调用并且不断返回下一个值，直到没有数据可取的对象称为迭代器： Iterator\n",
    "#可以使用isinstance()判断一个对象是否是iterator对象\n",
    "#生成器都是迭代器\n",
    "from collections import Iterator\n",
    "squares = (i**2 for i in range(5))\n",
    "print(isinstance(squares,Iterator))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "#列表 元组 字符串 字典 集合不是迭代器\n",
    "print(isinstance([1,2,3],Iterator))\n",
    "#可通过iter(iterable)创建迭代器\n",
    "print(isinstance(iter([1,2,3]),Iterator))\n",
    "#zip enumerate 等 itertools里的函数是迭代器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 'a')\n",
      "(2, 'b')\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "x = [1,2]\n",
    "y = [\"a\",\"b\"]\n",
    "zip(x,y)\n",
    "for i in zip(x,y):\n",
    "    print(i)\n",
    "print(isinstance(zip(x,y),Iterator))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "#文件是迭代器\n",
    "with open(\"test.txt\",\"r\",encoding=\"utf-8\") as f:\n",
    "    print(isinstance(f,Iterator))\n",
    "#迭代器是可耗尽的\n",
    "#range()不是迭代器,它不可以被next调用 且无法被耗尽，它是一种懒序列\n",
    "numbers = range(10)\n",
    "print(isinstance(numbers,Iterator))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'function'>\n",
      "25\n",
      "25\n"
     ]
    }
   ],
   "source": [
    "#装饰器\n",
    "#适用场景 需要对已经开发上线的程序添加某些功能，不能对程序中函数的源代码进行修改，不能改变程序中函数的调用方式\n",
    "#函数对象 函数是python中的第一类对象 可以把函数赋值给变量 对该变量进行调用 可实现原函数的功能\n",
    "def square(x):\n",
    "    return x**2\n",
    "print(type(square)) #square 是function类的一个实例\n",
    "pow_2 = square  #可以理解为给这个函数起了一个别名pow_2\n",
    "print(pow_2(5))\n",
    "print(square(5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "64\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "#可以将函数作为参数传递\n",
    "#高阶函数 接收函数作为参数，或者返回一个函数 满足这两个条件之一的函数称之为高阶函数\n",
    "def square1(x):\n",
    "    return x**2\n",
    "\n",
    "def pow_2(fun): #高阶函数\n",
    "    return fun\n",
    "\n",
    "f = pow_2(square1) #将square1这个函数作为参数赋值给pow_2,它的返回值还是square1这个函数\n",
    "print(f(8))\n",
    "print(f==square1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "outer is running\n",
      "inner is running\n"
     ]
    }
   ],
   "source": [
    "#嵌套函数 在函数的内部定义一个函数,并且调用\n",
    "def outer():\n",
    "    print(\"outer is running\")\n",
    "    def inner():\n",
    "        print(\"inner is running\")\n",
    "    inner()\n",
    "\n",
    "outer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<function outer1.<locals>.inner at 0x107918950>\n",
      "(101, 10)\n"
     ]
    }
   ],
   "source": [
    "#闭包\n",
    "#闭包是延伸了作用域的函数，如果一个函数定义在另一个函数作用域内，并且引用了外层函数的变量，则该函数称为闭包\n",
    "#闭包是由函数及其相关的引用环境组合而成的实体（即 闭包=函数+引用环境），即不但返回内部函数，还返回外部环境的引用\n",
    "def outer1():\n",
    "    x = 1\n",
    "    z = 10\n",
    "\n",
    "    def inner():\n",
    "        y = x + 100\n",
    "        return y,z\n",
    "    return inner\n",
    "\n",
    "f = outer1() #f实际上包含了inner函数本身+outer函数的环境\n",
    "print(f)\n",
    "res = f()\n",
    "print(res) #在inner函数中用到了outer函数的变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "11"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#一旦在内层函数重新定义了相同名字的变量，则变量成为局部变量\n",
    "def outer2():\n",
    "    x = 1\n",
    "    def inner():\n",
    "        #x = x + 100 #这里x定义在内层函数中，默认为局部变量，内层找不到x的值，所以报错\n",
    "        nonlocal x #用nonlocal声明x不是举报变量\n",
    "        x = x + 10\n",
    "        return x\n",
    "    return inner\n",
    "\n",
    "f = outer2()\n",
    "f()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "#一个简单的装饰器\n",
    "#嵌套函数的实现\n",
    "import time\n",
    "#定义timer装饰器函数\n",
    "def timer(func):\n",
    "    #定义嵌套函数inner\n",
    "    def inner():\n",
    "        print(\"inner run\")\n",
    "        start = time.time()\n",
    "        #在inner中运行传递过来的函数，并且在前后用两个时间戳获得它运行的时间\n",
    "        func()\n",
    "        end = time.time()\n",
    "        print(\"{}函数运行用时{:.2f}秒\".format(func.__name__,(end-start)))\n",
    "    return inner()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义一个f1函数，我们希望它在运行的时候，统计一下用了多长时间\n",
    "def f1():\n",
    "    print(\"f1 run\")\n",
    "    time.sleep(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "inner run\n",
      "f1 run\n",
      "f1函数运行用时1.00秒\n"
     ]
    }
   ],
   "source": [
    "#将f1函数传递到timer()函数里面去，返回值是inner，此时返回值f1不单单包括inner函数，还包括timer函数的外部环境，包括参数func\n",
    "f1 = timer(f1)\n",
    "f1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "inner run\n",
      "f1 run\n",
      "f2函数运行用时1.00秒\n"
     ]
    }
   ],
   "source": [
    "#语法糖\n",
    "@timer    #相当于实现了f2 = timer(f2)\n",
    "def f2():\n",
    "    print(\"f1 run\")\n",
    "    time.sleep(1)\n",
    "f2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "inner run\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "f3() missing 2 required positional arguments: 'n1' and 'n2'",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "\u001B[0;32m<ipython-input-40-379d95c679d4>\u001B[0m in \u001B[0;36m<module>\u001B[0;34m()\u001B[0m\n\u001B[1;32m     11\u001B[0m     \u001B[0;32mreturn\u001B[0m \u001B[0minner\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m     12\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m---> 13\u001B[0;31m \u001B[0;34m@\u001B[0m\u001B[0mtimer1\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m     14\u001B[0m \u001B[0;32mdef\u001B[0m \u001B[0mf3\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mn1\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0mn2\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m     15\u001B[0m     \u001B[0mprint\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m\"f3 run\"\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n",
      "\u001B[0;32m<ipython-input-40-379d95c679d4>\u001B[0m in \u001B[0;36mtimer1\u001B[0;34m(func)\u001B[0m\n\u001B[1;32m      9\u001B[0m         \u001B[0mend\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mtime\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mtime\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m     10\u001B[0m         \u001B[0mprint\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m\"{}函数运行用时{:.2f}秒\"\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mformat\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mfunc\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0m__name__\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mend\u001B[0m\u001B[0;34m-\u001B[0m\u001B[0mstart\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m---> 11\u001B[0;31m     \u001B[0;32mreturn\u001B[0m \u001B[0minner\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m     12\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m     13\u001B[0m \u001B[0;34m@\u001B[0m\u001B[0mtimer1\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n",
      "\u001B[0;32m<ipython-input-40-379d95c679d4>\u001B[0m in \u001B[0;36minner\u001B[0;34m(*args, **kwargs)\u001B[0m\n\u001B[1;32m      6\u001B[0m         \u001B[0mstart\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mtime\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mtime\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m      7\u001B[0m         \u001B[0;31m#在inner中运行传递过来的函数，并且在前后用两个时间戳获得它运行的时间\u001B[0m\u001B[0;34m\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m----> 8\u001B[0;31m         \u001B[0mfunc\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m*\u001B[0m\u001B[0margs\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m**\u001B[0m\u001B[0mkwargs\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m      9\u001B[0m         \u001B[0mend\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mtime\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mtime\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m     10\u001B[0m         \u001B[0mprint\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m\"{}函数运行用时{:.2f}秒\"\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mformat\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mfunc\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0m__name__\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mend\u001B[0m\u001B[0;34m-\u001B[0m\u001B[0mstart\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n",
      "\u001B[0;31mTypeError\u001B[0m: f3() missing 2 required positional arguments: 'n1' and 'n2'"
     ]
    }
   ],
   "source": [
    "#装饰有参函数\n",
    "def timer1(func):\n",
    "    #定义嵌套函数inner\n",
    "    def inner(*args, **kwargs):\n",
    "        print(\"inner run\")\n",
    "        start = time.time()\n",
    "        #在inner中运行传递过来的函数，并且在前后用两个时间戳获得它运行的时间\n",
    "        func(*args,**kwargs)\n",
    "        end = time.time()\n",
    "        print(\"{}函数运行用时{:.2f}秒\".format(func.__name__,(end-start)))\n",
    "    return inner()\n",
    "\n",
    "@timer1\n",
    "def f3(n1,n2):\n",
    "    print(\"f3 run\")\n",
    "    time.sleep(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "#f3(3) 报错？\n",
    "\n",
    "\n",
    "#装饰器本身也要传递一些额外的参数 理解闭包是关键\n",
    "\n",
    "#何时执行装饰器 一装饰就执行 不必等调用\n",
    "#通过python内部装饰器 @wraps可以将掩饰掉的原函数的属性重新回来"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}